﻿/* 
 * Copyright 2010 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using Ngilead.Core.Exception;
using Iesi.Collections;

namespace Ngilead.Core.Replicator
{
    public class SetReplicator : AbstractReplicator
    {
        #region Attributes

        /// <summary> Logger channel</summary>
        private static ILog logger = LogManager.GetLogger(typeof(SetReplicator));

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public SetReplicator()
        { }

        #endregion

        #region Public interface

        /// <summary>
        /// Replicate the argument collection, using the toClass for different class handling.
        /// </summary>
        public virtual T ReplicateSet<T>(T fromSet) where T : ISet
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info(String.Format("ReplicateSet<T>(fromCollection) : where T is {0}", typeof(T).ToString()));
            }

            T toCollection;
            try
            {
                toCollection = CreateToSet(fromSet);

                // put TargetCloned
                PutTargetCloned(fromSet, toCollection);

                // recursively populate member objects.
                foreach (Object fromMember in fromSet)
                {
                    if (fromMember == null)
                    {
                        Type GType = fromSet.GetType().GetGenericArguments()[0];
                        toCollection.Add(GType.IsValueType ? Activator.CreateInstance(GType) : null);
                    }
                    else
                    {
                        toCollection.Add(BeanTransformer.Replicate(fromMember));
                    }
                }
            }
            catch (System.Exception ex)
            {
                throw new CloneException(ex.Message, ex);
            }

            return toCollection;
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Create a new (empty) set of the same type as the argument
        /// </summary>
        /// <typeparam name="T">ISet</typeparam>
        /// <param name="from">The input collection</param>
        /// <returns>The new empty collection</returns>
        protected virtual T CreateToSet<T>(T from) where T : ISet
        {
            return CollectionUtil.CreateToSet(from);
        }

        #endregion
    }
}

